/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cageballserver.io;

import cageballcommon.messages.InitTeam;
import cageballcommon.exceptions.CageballIOException;
import cageballcommon.io.interfaces.CageballWriter;
import cageballcommon.io.impl.CageballSocketIO;
import cageballcommon.messages.State;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author kanonas
 */
public class ObserverServer implements Runnable {

    private int port;
    private ServerSocket socket;
    private LinkedList<CageballWriter> connections;
    private LinkedList<CageballWriter> remove;
    private boolean active;
    private Properties gameProperties;
    private InitTeam team1;
    private InitTeam team2;
    private Thread thread;
    private boolean running;

    public ObserverServer(int port) throws IOException {
        this.port = port;

        connections = new LinkedList<CageballWriter>();
        remove = new LinkedList<CageballWriter>();
    }

    public synchronized void init(Properties gameProperties, InitTeam team1, InitTeam team2) {
        this.gameProperties = gameProperties;
        this.team1 = team1;
        this.team2 = team2;
        for (CageballWriter writer : connections) {
            try {
                writer.writeProperties(gameProperties);
                writer.writeInitTeam(team1);
                writer.writeInitTeam(team2);
            } catch (CageballIOException ex) {
                Logger.getLogger(ObserverServer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        active = true;

    }

    private synchronized void addConnection(CageballWriter writer) throws IOException {

        connections.add(writer);

        if (active) {
            try {
                writer.writeProperties(gameProperties);
                writer.writeInitTeam(team1);
                writer.writeInitTeam(team2);
            } catch (CageballIOException ex) {
                Logger.getLogger(ObserverServer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

   public synchronized void sendState(State state) {

        for (CageballWriter writer : connections) {
            try {
                writer.writeState(state);
            } catch (CageballIOException ex) {
                try {
                    writer.close();
                } catch (CageballIOException ex1) {
                }
                remove.add(writer);
            }
        }

        if (!remove.isEmpty()) {
            connections.removeAll(remove);
            remove.clear();
        }
    }

    public synchronized void endGame() {
        active = false;
    }

    public void run() {

        Socket tmp;

        while (running) {
            try {
                tmp = socket.accept();
                addConnection(new CageballSocketIO(tmp));
                System.out.println("Observer connected: " + tmp.getRemoteSocketAddress());
            } catch (IOException ex) {
            }
        }
    }

    public void start() throws IOException {
        running = true;
        socket = new ServerSocket(port);
        thread = new Thread(this);
        thread.start();
    }

    public synchronized void stop() throws IOException {
        running = false;
        thread.interrupt();

        for(CageballWriter io:connections){
            try {
                io.close();
            } catch (CageballIOException ex) {
            }
        }
        socket.close();
    }
}
